import 'package:backdrop/backdrop.dart';
import 'package:flutter/material.dart';
import 'package:flutter_2b_client/apis/FactoryApi.dart';
import 'package:flutter_2b_client/apis/GoodsBrandApi.dart';
import 'package:flutter_2b_client/apis/GoodsCategoryApi.dart';
import 'package:flutter_2b_client/components/FormItem.dart';
import 'package:flutter_2b_client/model/IntIdAndName.dart';
import 'package:flutter_2b_client/store/EmployeeAuthorizationStore.dart';
import 'package:flutter_2b_client/utils/MobxHooks.dart';
import 'package:flutter_2b_client/utils/Page.dart';
import 'package:flutter_2b_client/utils/PagingUtils.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';

import '../apis/GoodsApi.dart';
import '../components/CheckboxWrap.dart';
import '../components/FilterBackLayerLayout.dart';
import '../components/PageableQueryFrontLayer.dart';
import 'AddGoodsPage.dart';

part 'GoodsPage.g.dart';

part 'GoodsPage.freezed.dart';

class GoodsPage extends HookWidget {
  final int? editMarketOrderId;
  final int? editMarketDeliveryOrderId;
  final int? editCheckInventoryRecordId;
  final int? editMarketCheckInventoryRecordId;
  final bool? returnItem;
  final bool? multiSelect;
  final List<int> excludeIds;

  const GoodsPage({
    Key? key,
    this.editMarketOrderId,
    this.editMarketDeliveryOrderId,
    this.editCheckInventoryRecordId,
    this.multiSelect,
    this.returnItem,
    this.excludeIds = const [],
    this.editMarketCheckInventoryRecordId,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var pagingController =
        usePagingController<Pageable, GoodsBasic>(firstPageKey: Pageable());
    var totalElementsState = useState(0);
    var goodsFilterDataState = useState(const GoodsFilterData(
      brandIds: [],
      categoryIds: [],
      factoryIds: [],
    ));
    usePagingControllerListener(
        pagingController,
        (pageable) => goodsApi.queryGoodsBasic({
              ...pageable.toRequestParamsMap(),
              if (goodsFilterDataState.value.nameOrBarcode != null)
                "nameOrBarcode": goodsFilterDataState.value.nameOrBarcode,
              "brandIds": goodsFilterDataState.value.brandIds,
              "categoryIds": goodsFilterDataState.value.categoryIds,
              "editMarketOrderId": editMarketOrderId,
              "factoryIds": goodsFilterDataState.value.factoryIds,
              "onlyNew": goodsFilterDataState.value.onlyNew,
              "editCheckInventoryRecordId": editCheckInventoryRecordId,
              "editMarketDeliveryOrderId": editMarketDeliveryOrderId,
              "editMarketCheckInventoryRecordId":
                  editMarketCheckInventoryRecordId,
              "excludeIds": excludeIds,
            }).then((value) {
              totalElementsState.value = value.totalElements;
              return value;
            }),
        null,
        [
          goodsFilterDataState.value,
          editMarketOrderId,
          editCheckInventoryRecordId,
          editMarketDeliveryOrderId,
          editMarketCheckInventoryRecordId,
          excludeIds,
        ]);
    final isSelectGoods = useMemoized(
        () => [
              editMarketOrderId,
              editCheckInventoryRecordId,
              editMarketDeliveryOrderId,
              editMarketCheckInventoryRecordId,
              returnItem,
              multiSelect,
            ].any((element) => element != null),
        [
          editMarketOrderId,
          editCheckInventoryRecordId,
          editMarketDeliveryOrderId,
          editMarketCheckInventoryRecordId,
          returnItem,
          multiSelect,
        ]);

    var textEditingController = useTextEditingController();

    final selectedIdsState = useState<List<int>>([]);
    var employeeAuthorizationStore =
        Provider.of<EmployeeAuthorizationStore>(context);
    var me = useObservable(() => employeeAuthorizationStore.me);
    var backLayerRevealedState = useState(false);
    return BackdropScaffold(
      backLayerBackgroundColor: Theme.of(context).colorScheme.primaryContainer,
      floatingActionButton: me?.hasAuthority("货品_新增") == true
          ? Visibility(
              visible: !backLayerRevealedState.value,
              child: FloatingActionButton(
                onPressed: () async {
                  await context.push("/goods/new");
                },
                child: const Icon(Icons.add),
              ),
            )
          : null,
      appBar: AppBar(
        title: const Text("商品"),
        backgroundColor: Theme.of(context).colorScheme.primaryContainer,
        actions: [
          BackdropToggleButton(
            icon: AnimatedIcons.close_menu,
            color: goodsFilterDataState.value.hasAnyFilter
                ? Theme.of(context).colorScheme.tertiary
                : Theme.of(context).colorScheme.onPrimaryContainer,
          ),
          IconButton(
            onPressed: () async {
              var barcode = await context.push("/scanBarcode") as String?;
              if (barcode != null) {
                textEditingController.text = barcode;
                goodsFilterDataState.value =
                    goodsFilterDataState.value.copyWith(nameOrBarcode: barcode);
              }
            },
            icon: const Icon(Icons.document_scanner_rounded),
          ),
          if (multiSelect == true)
            IconButton(
              onPressed: () async {
                if (returnItem == true) {
                  context.pop(pagingController.itemList
                          ?.where((element) =>
                              selectedIdsState.value.contains(element.id))
                          .toList() ??
                      []);
                } else {
                  context.pop();
                }
              },
              icon: const Icon(Icons.check),
            ),
        ],
      ),
      backLayer: GoodsFilterBackLayer(
        nameOrBarcodeTextEditingController: textEditingController,
        onConfirm: (GoodsFilterData data) {
          goodsFilterDataState.value = data;
        },
      ),
      onBackLayerRevealed: () {
        backLayerRevealedState.value = true;
      },
      onBackLayerConcealed: () {
        backLayerRevealedState.value = false;
      },
      frontLayer: PageableQueryFrontLayer(
        pagingController: pagingController,
        total: totalElementsState.value,
        itemBuilder: (BuildContext context, GoodsBasic item, int index) {
          return GoodsListItem(
            item,
            key: Key(item.id.toString()),
            onPressed: isSelectGoods
                ? () {
                    if (multiSelect == true) {
                      selectedIdsState.value = selectedIdsState.value.toList()
                        ..add(item.id);
                    } else {
                      context.pop(returnItem == true ? item : item.id);
                    }
                  }
                : () {
                    context.push("/goods/${item.id}");
                  },
            checkable: multiSelect == true,
            checked: selectedIdsState.value.contains(item.id),
            onChange: (value) {
              if (value) {
                selectedIdsState.value = selectedIdsState.value.toList()
                  ..add(item.id);
              } else {
                selectedIdsState.value = selectedIdsState.value.toList()
                  ..remove(item.id);
              }
            },
          );
        },
        resource: "商品",
      ),
    );
  }
}

@freezed
class GoodsFilterData with _$GoodsFilterData {
  const factory GoodsFilterData({
    String? nameOrBarcode,
    required List<int> brandIds,
    required List<int> categoryIds,
    required List<int> factoryIds,
    @Default(false) bool onlyNew,
  }) = _GoodsFilterData;

  const GoodsFilterData._();

  factory GoodsFilterData.fromJson(Map<String, dynamic> json) =>
      _$GoodsFilterDataFromJson(json);

  bool get hasAnyFilter {
    return nameOrBarcode?.isNotEmpty == true ||
        brandIds.isNotEmpty ||
        categoryIds.isNotEmpty;
  }
}

class GoodsFilterBackLayer extends HookWidget {
  final void Function(GoodsFilterData data) onConfirm;
  final TextEditingController nameOrBarcodeTextEditingController;

  const GoodsFilterBackLayer(
      {Key? key,
      required this.onConfirm,
      required this.nameOrBarcodeTextEditingController})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    var textState = useState("");

    var brandsState = useState<List<IntIdAndName>>([]);
    useEffect(() {
      goodsBrandApi
          .getAllGoodsBrands()
          .then((value) => brandsState.value = value);
      return null;
    }, []);
    final selectedBrandIdsState = useState<List<int>>([]);

    var categoriesState = useState<List<IntIdAndName>>([]);
    useEffect(() {
      goodsCategoryApi
          .getAllGoodsCategories()
          .then((value) => categoriesState.value = value);
      return null;
    }, []);
    final selectedCategoryIdsState = useState<List<int>>([]);

    var factoriesState = useState<List<IntIdAndName>>([]);
    useEffect(() {
      factoryApi
          .getAllFactories()
          .then((value) => factoriesState.value = value);
      return null;
    }, []);
    final selectedFactoryIdsState = useState<List<int>>([]);

    final onlyNewState = useState(false);
    return FilterBackLayerLayout(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          FormItem(
            label: "仅新品",
            child: Padding(
              padding: const EdgeInsets.only(top: 8.0),
              child: Switch(
                value: onlyNewState.value,
                onChanged: (value) => onlyNewState.value = value,
              ),
            ),
          ),
          FormItem(
            label: "条码和名称",
            child: Padding(
              padding: const EdgeInsets.only(top: 8.0),
              child: TextField(
                controller: nameOrBarcodeTextEditingController,
                onChanged: (value) => textState.value = value,
                decoration: const InputDecoration(
                    border: OutlineInputBorder(gapPadding: 0),
                    isDense: true,
                    contentPadding:
                        EdgeInsets.symmetric(horizontal: 8, vertical: 6)),
              ),
            ),
          ),
          FormItem(
            label: "品牌",
            child: CheckboxWrap(
              elements: brandsState.value,
              getKey: (IntIdAndName e) {
                return e.id;
              },
              getLabel: (IntIdAndName e) {
                return e.name;
              },
              selectedKeys: selectedBrandIdsState.value,
              onChange: (keys) => selectedBrandIdsState.value = keys,
            ),
          ),
          FormItem(
            label: "分类",
            child: CheckboxWrap(
              elements: categoriesState.value,
              getKey: (IntIdAndName e) {
                return e.id;
              },
              getLabel: (IntIdAndName e) {
                return e.name;
              },
              selectedKeys: selectedCategoryIdsState.value,
              onChange: (keys) => selectedCategoryIdsState.value = keys,
            ),
          ),
          FormItem(
            label: "厂商",
            child: CheckboxWrap(
              elements: factoriesState.value,
              getKey: (IntIdAndName e) {
                return e.id;
              },
              getLabel: (IntIdAndName e) {
                return e.name;
              },
              selectedKeys: selectedFactoryIdsState.value,
              onChange: (keys) => selectedFactoryIdsState.value = keys,
            ),
          ),
        ],
      ),
      onConfirm: () {
        onConfirm(GoodsFilterData(
          brandIds: selectedBrandIdsState.value,
          categoryIds: selectedCategoryIdsState.value,
          nameOrBarcode: textState.value.isEmpty ? null : textState.value,
          factoryIds: selectedFactoryIdsState.value,
          onlyNew: onlyNewState.value,
        ));
        Backdrop.of(context).concealBackLayer();
      },
      onClear: () {
        selectedCategoryIdsState.value = [];
        selectedBrandIdsState.value = [];
        textState.value = "";
      },
    );
  }
}

class GoodsListItem extends HookWidget {
  final GoodsBasic item;
  final VoidCallback? onPressed;
  final bool checkable;
  final bool checked;
  final ValueChanged<bool>? onChange;

  const GoodsListItem(this.item,
      {Key? key,
      this.onPressed,
      this.checkable = false,
      this.checked = false,
      this.onChange})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return checkable
        ? CheckboxListTile(
            title: Text(item.name),
            dense: true,
            subtitle:
                Text("${item.barcode}\n库存：${item.amount}      ￥${item.price}"),
            isThreeLine: true,
            value: checked,
            onChanged: (value) {
              if (onChange != null) {
                onChange!(value ?? false);
              }
            },
          )
        : ListTile(
            title: Text(item.name),
            dense: true,
            subtitle:
                Text("${item.barcode}\n库存：${item.amount}      ￥${item.price}"),
            isThreeLine: true,
            onTap: onPressed,
          );
  }
}
